--operators
function __add(a,b) return a+b end
function __sub(a,b) return a-b end
function __mul(a,b) return a*b end
function __div(a,b) return a/b end
function __mod(a,b) return a%b end
function __pow(a,b) return a^b end
function __concat(a,b) return a..b end
function __unm(a) return -a end

function __eq(a,b) return a==b end
function __ne(a,b) return a~=b end
function __lt(a,b) return a<b end
function __le(a,b) return a<=b end
function __gt(a,b) return a>b end
function __ge(a,b) return a>=b end

function __index(t,k) return t[k] end

--functional
func={}
function func.compose(f,g) return function(...) return f(g(...)) end end
function func.pswap(f) return function(a,b,...) return f(b,a,...) end end
function func.pbind(f,a) return function(...) return f(a,...) end end
function func.pbind2(f,a) return function(b,...) return f(b,a,...) end end

--list operations
function table.transform(lst,fn,...) for i=1,#lst do lst[i]=fn(lst[i],...) end return lst end
function table.transform2(lst,oth,fn,...) for i=1,(#lst>#oth and #lst or #oth) do lst[i]=fn(lst[i],oth[i],...) end return lst end
function table.push(lst,...) for i=1,select('#',...) do lst[#lst+1]=select(i,...) end return lst end
function table.reduce(lst,fn,def) for i=1,#lst do def=fn(def,lst[i]) end return def end
function table.index(lst,v) for i=1,#lst do if lst[i]==v then return i end end end
function table.setify(lst,set) for i=1,#lst do set[lst[i]]=true end return set end
function table.map(lst,fn,...) local t={} for i=1,#lst do t[i]=fn(lst[i],...) end return t end

--math operations
local function sum(a,...) for i=1,select('#',...) do a=a+select(i,...) end return a end

math.sum=sum
function math.bound(v,l,u) return v>u and u or (v<l and l or v) end
function math.mod1(v,c) return (v-1)%c+1 end
function math.round(v,p) v=v+p/2 return v-math.fmod(v,p) end
function math.avg(a,...) return sum(a,...)/(1+select('#',...)) end
function math.sgn(a) return a<0 and -1 or (a>0 and 1 or 0) end
function math.normal2()
  local u,v=1-math.random(),1-math.random()
  local coeff=math.sqrt(-2*math.log(u))
  return coeff*math.cos(math.pi*2*v), coeff*math.sin(math.pi*2*v)
end
  


